PersisterRegistry.java
package org.codefilarete.stalactite.engine;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.codefilarete.stalactite.engine.runtime.BeanPersister;
import org.codefilarete.tool.Reflections;
import org.codefilarete.tool.collection.Iterables;
/**
* Contract for {@link BeanPersister} registry.
*
* @author Guillaume Mary
*/
public interface PersisterRegistry {
/**
* Returns the {@link BeanPersister} mapped for a class.
*
* @param clazz the class for which the {@link BeanPersister} must be given
* @param <C> the type of the persisted entity
* @return null if class has no persister registered
* @throws IllegalArgumentException if the class is not mapped
*/
<C, I> EntityPersister<C, I> getPersister(Class<C> clazz);
/**
* Registers a {@link BeanPersister} on this instance. May overwrite an existing one
*
* @param persister any {@link BeanPersister}
* @param <C> type of persisted bean
*/
<C> void addPersister(EntityPersister<C, ?> persister);
/**
* Returns all registered persisters
* @return a set of all registered persisters
*/
Set<EntityPersister> getPersisters();
class DefaultPersisterRegistry implements PersisterRegistry {
private final Map<Class<?>, EntityPersister> persisterCache;
public DefaultPersisterRegistry() {
this.persisterCache = new HashMap<>();
}
public DefaultPersisterRegistry(Set<EntityPersister> persisters) {
this.persisterCache = Iterables.map(persisters, EntityPersister::getClassToPersist, p -> p, HashMap::new);
}
/**
* Looks for an {@link EntityPersister} registered for given class or one of its parent.
* Found persister is then capable of persisting any instance of given class.
* Made as such to take into account inheritance of a given entity and be capable of writing such code:
* <pre>{@code
* // this would work even if entity is a subtype of an aggregate root persister registered in the registry
* persisterRegistry.getPersister(entity.getClass()).insert(entity);
* }</pre>
*
* @param clazz the class for which the {@link EntityPersister} must be given
* @param <C> the type of the persisted entity
* @return null if class has no compatible persister registered
*/
@Override
public <C, I> EntityPersister<C, I> getPersister(Class<C> clazz) {
return persisterCache.get(clazz);
}
/**
* Registers a {@link EntityPersister} on this instance. May overwrite an existing one
*
* @param persister any {@link EntityPersister}
* @param <C> type of persisted bean
* @throws IllegalArgumentException if a persister already exists for class persisted by given persister
*/
@Override
public <C> void addPersister(EntityPersister<C, ?> persister) {
EntityPersister<C, ?> existingPersister = persisterCache.get(persister.getClassToPersist());
if (existingPersister != null && existingPersister != persister) {
throw new UnsupportedOperationException("Persister already exists for class " + Reflections.toString(persister.getClassToPersist()));
}
persisterCache.put(persister.getClassToPersist(), persister);
}
@Override
public Set<EntityPersister> getPersisters() {
// copy the Set because values() is backed by the Map and getPersisters() is not expected to permit such modification
return new HashSet<>(persisterCache.values());
}
}
}